package com.yf.repo.modules.qu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.base.api.api.dto.BaseBatchReqDTO;
import com.yf.base.api.api.dto.PagingReqDTO;
import com.yf.base.api.exception.ServiceException;
import com.yf.base.utils.BeanMapper;
import com.yf.repo.enums.QuType;
import com.yf.repo.modules.qu.dto.QuAnswerDTO;
import com.yf.repo.modules.qu.dto.QuDTO;
import com.yf.repo.modules.qu.dto.export.QuExportDTO;
import com.yf.repo.modules.qu.dto.ext.QuDetailDTO;
import com.yf.repo.modules.qu.dto.request.ChapterGroupReqDTO;
import com.yf.repo.modules.qu.dto.request.ChapterJoinReqDTO;
import com.yf.repo.modules.qu.dto.request.LevelSetReqDTO;
import com.yf.repo.modules.qu.dto.request.QuQueryReqDTO;
import com.yf.repo.modules.qu.entity.Course;
import com.yf.repo.modules.qu.entity.CourseRepo;
import com.yf.repo.modules.qu.entity.Qu;
import com.yf.repo.modules.qu.mapper.CourseMapper;
import com.yf.repo.modules.qu.mapper.CourseRepoMapper;
import com.yf.repo.modules.qu.mapper.QuMapper;
import com.yf.repo.modules.qu.service.QuAnswerService;
import com.yf.repo.modules.qu.service.QuService;
import com.yf.repo.modules.qu.utils.QuConvert;
import com.yf.repo.modules.repo.dto.response.ChapterGroupDTO;
import com.yf.repo.modules.repo.dto.response.LevelGroupDTO;
import com.yf.repo.modules.repo.entity.Repo;
import com.yf.repo.modules.repo.mapper.RepoMapper;
import com.yf.system.modules.user.UserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

/**
 * <p>
 * 语言设置 服务实现类
 * </p>
 *
 * @author 聪明笨狗
 * @since 2020-05-25 10:17
 */
@Service
public class QuServiceImpl extends ServiceImpl<QuMapper, Qu> implements QuService {

    @Autowired
    private QuAnswerService quAnswerService;

    @Autowired
    private QuConvert quConvert;

    @Autowired
    @Qualifier("courseRepoMapperFromQu")
    private CourseRepoMapper courseRepoMapper;

    @Autowired
    @Qualifier("courseMapperFromQu")
    private CourseMapper courseMapper;

    @Autowired
    private RepoMapper repoMapper;

    @Override
    public IPage<QuDTO> paging(PagingReqDTO<QuQueryReqDTO> reqDTO) {

        // 创建分页对象
        Page page = reqDTO.toPage();

        // 转换结果
        IPage<QuDTO> pageData = baseMapper.paging(page, reqDTO.getParams());
        return pageData;
    }

    @Override
    public IPage<QuDetailDTO> pagingWithAnswer(PagingReqDTO<QuQueryReqDTO> reqDTO) {
        // 创建分页对象
        Page page = reqDTO.toPage();

        // 转换结果
        IPage<QuDetailDTO> pageData = baseMapper.pagingWithAnswer(page, reqDTO.getParams());
        return pageData;
    }

    @Override
    public List<QuDetailDTO> listWithChapterGroup(ChapterGroupDTO req, List<String> excludes) {

        List<LevelGroupDTO> levels = req.getLevels();
        List<QuDetailDTO> list = new ArrayList<>();

        for (LevelGroupDTO item : levels) {

            if (item.getNum() == 0) {
                continue;
            }
            QuQueryReqDTO quDTO = new QuQueryReqDTO();
            quDTO.setRepoId(req.getRepoId());
            quDTO.setQuType(req.getQuType());
            quDTO.setLevel(item.getLevel());
            quDTO.setChapterId(req.getChapterId());
            quDTO.setExcludes(excludes);
            List<QuDetailDTO> levelList = baseMapper.listByRand(quDTO, item.getNum());
            if (CollectionUtils.isEmpty(levelList) || levelList.size() < item.getNum()) {
                throw new ServiceException("题库数量不足！");
            }

            // 加入所有
            list.addAll(levelList);
        }

        return list;
    }

    @Override
    public List<QuDetailDTO> listWithChapterGroup(ChapterGroupReqDTO reqDTO) {
        List<QuDetailDTO> list = new ArrayList<>();
        for (ChapterGroupDTO item : reqDTO.getItems()) {
            list.addAll(this.listWithChapterGroup(item, reqDTO.getExcludes()));
        }
        return list;
    }

    @Override
    public QuDetailDTO detail(String id) {

        QuDetailDTO respDTO = new QuDetailDTO();
        Qu qu = this.getById(id);
        BeanMapper.copy(qu, respDTO);

        // 普通答案选项
        List<QuAnswerDTO> answerList = quAnswerService.listByQu(id);
        respDTO.setAnswerList(answerList);

        // 查找子题目
        if (QuType.MIX.equals(qu.getQuType())) {
            List<QuDetailDTO> subList = this.listSub(id);
            respDTO.setSubList(subList);
        }

        return respDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(QuDetailDTO reqDTO) {

        // 校验数据
        this.checkData(reqDTO);

        Qu qu = new Qu();
        BeanMapper.copy(reqDTO, qu);

        // 更新
        this.saveOrUpdate(qu);

        // 保存全部问题
        quAnswerService.saveAll(qu.getId(), reqDTO.getAnswerList());

        // 保存组合题
        if (QuType.MIX.equals(reqDTO.getQuType())) {
            List<QuDetailDTO> subList = reqDTO.getSubList();

            int i = 1;
            for (QuDetailDTO item : subList) {
                // 保存子题目
                Qu sub = new Qu();
                BeanMapper.copy(item, sub);
                sub.setChild(true);
                sub.setRefId(qu.getId());
                sub.setSort(i);
                // 更新
                this.saveOrUpdate(sub);
                // 保存全部问题
                quAnswerService.saveAll(sub.getId(), item.getAnswerList());
                i++;
            }
        }
    }

    /**
     * 保存题目，题目、答案等都用的JSON格式
     * 
     * @param reqDTO
     */
    public void saveJson(List<Qu> reqDTO, String courseId, String userId) {
        CourseRepo courseRepo = courseRepoMapper.selectOne(new QueryWrapper<CourseRepo>().eq("course_id", courseId));
        String repoId;
        if (courseRepo == null) {
            // el_repo 新增
            Course course = courseMapper.selectById(courseId);
            Repo repo = new Repo();
            repo.setTitle(course.getTitle() + "题库");
            repoMapper.insert(repo);
            repoId = repo.getId();
            // el_course_repo 新增
            courseRepo = new CourseRepo();
            courseRepo.setId(null);
            courseRepo.setCourseId(courseId);
            courseRepo.setRepoId(repoId);
            courseRepoMapper.insert(courseRepo);
        } else {
            repoId = courseRepo.getRepoId();
        }

        // 逐条处理，支持 JSON 内容拆解为字段与答案
        for (Qu item : reqDTO) {
            item.setRepoId(repoId);
            item.setCreateBy(userId);
            item.setUpdateBy(userId);

            String content = item.getContent();
            if (content != null && content.trim().startsWith("{")) {
                // 将 JSON 反序列化并拆解到 QuDetailDTO，再复用现有保存逻辑
                try {
                    JSONObject obj = JSON.parseObject(content.trim());
                    QuDetailDTO dto = parseJsonToDetail(obj, item.getQuType(), item.getLevel());
                    // 继承仓库/章节/等级等可能由列表项直接给出的字段
                    if (StringUtils.isEmpty(dto.getRepoId())) {
                        dto.setRepoId(repoId);
                    }
                    dto.setCreateBy(userId);
                    dto.setUpdateBy(userId);
                    // 使用已有 save 方法，负责写入题目、答案和组合题子题
                    this.save(dto);
                } catch (Exception e) {
                    throw new ServiceException("JSON题目解析失败：" + e.getMessage());
                }
            } else {
                // 非 JSON 内容，按原字段直接保存
                if (item.getRefId() == null || item.getRefId().isEmpty()) {
                    item.setChild(false);
                } else {
                    item.setChild(true);
                }
                this.saveOrUpdate(item);
            }
        }
    }

    @Override
    public List<QuExportDTO> listForExport(QuQueryReqDTO query) {

        Page page = new Page();
        page.setCurrent(1);
        page.setSize(Integer.MAX_VALUE);

        IPage<QuDetailDTO> pageData = baseMapper.pagingWithAnswer(page, query);
        List<QuDetailDTO> list = pageData.getRecords();
        List<QuExportDTO> respList = new ArrayList<>();

        // 构建导出结果
        quConvert.buildExport(respList, list, false);

        return respList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importExcel(List<QuExportDTO> list, String repoId) {
        // 校验并转换
        List<QuDetailDTO> dtoList = quConvert.prepareImport(list, repoId);

        // 循环题目插入
        for (QuDetailDTO dto : dtoList) {
            // 保存答案
            this.save(dto);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<String> ids) {

        // 删除题目
        this.removeByIds(ids);

        // 移除子题目
        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(Qu::getRefId, ids);
        this.remove(wrapper);

        // 移除答案
        quAnswerService.removeByQuIds(ids);

        // 移除引用
        this.removeRefs(ids);

    }

    @Override
    public List<Qu> listForTrain(String repoId, String quType, boolean rand) {

        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .select(Qu::getId, Qu::getQuType, Qu::getChild, Qu::getRefId)
                .eq(Qu::getChild, false)
                .eq(Qu::getRepoId, repoId);

        if (!StringUtils.isEmpty(quType)) {
            wrapper.lambda().eq(Qu::getQuType, quType);
        }

        if (rand) {
            wrapper.orderByAsc(" RAND() ");
        }

        return this.list(wrapper);
    }

    @Override
    public List<Qu> listByRef(String refId) {
        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .select(Qu::getId, Qu::getQuType, Qu::getChild, Qu::getRefId)
                .eq(Qu::getRefId, refId);

        return this.list(wrapper);
    }

    @Override
    public void joinChapters(ChapterJoinReqDTO reqDTO) {

        List<String> quIds = reqDTO.getQuIds();

        if (CollectionUtils.isEmpty(quIds)) {
            return;
        }

        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(Qu::getId, quIds);

        Qu qu = new Qu();
        qu.setChapterId(reqDTO.getChapterId());
        this.update(qu, wrapper);
    }

    @Override
    public void clearChapters(ChapterJoinReqDTO reqDTO) {

        List<String> quIds = reqDTO.getQuIds();

        if (CollectionUtils.isEmpty(quIds)) {
            return;
        }

        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(Qu::getId, quIds);

        Qu qu = new Qu();
        qu.setChapterId("");
        this.update(qu, wrapper);
    }

    @Override
    public void batchLevel(LevelSetReqDTO reqDTO) {

        List<String> quIds = reqDTO.getQuIds();

        if (CollectionUtils.isEmpty(quIds)) {
            return;
        }

        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(Qu::getId, quIds);

        Qu qu = new Qu();
        qu.setLevel(reqDTO.getLevel());
        this.update(qu, wrapper);
    }

    @Override
    public void batchRepo(BaseBatchReqDTO reqDTO) {

        List<String> quIds = reqDTO.getIds();

        if (CollectionUtils.isEmpty(quIds)) {
            return;
        }

        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(Qu::getId, quIds);

        Qu qu = new Qu();
        qu.setRepoId(reqDTO.getToId());
        // 清除章节
        qu.setChapterId("");
        this.update(qu, wrapper);
    }

    @Override
    public int countByRepo(String repoId) {
        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(Qu::getRepoId, repoId);

        return this.count(wrapper);
    }

    /**
     * 校验题目信息
     *
     * @param qu
     * @throws Exception
     */
    public void checkData(QuDetailDTO qu) {

        // 试题内容截取
        String content = qu.getContentText();

        if (StringUtils.isEmpty(qu.getContent())) {
            throw new ServiceException(MessageFormat.format("题目：【{0}】，题目内容或图片至少一个不能为空！", content));
        }

        if (StringUtils.isEmpty(qu.getRepoId())) {
            throw new ServiceException(MessageFormat.format("题目：【{0}】，至少要选择一个题库！", content));
        }

        List<QuAnswerDTO> answers = qu.getAnswerList();

        // 题型
        String quType = qu.getQuType();

        // 组合题校验
        if (QuType.MIX.equals(quType)) {

            List<QuDetailDTO> subList = qu.getSubList();
            if (CollectionUtils.isEmpty(subList)) {
                throw new ServiceException(MessageFormat.format("题目：【{0}】，组合题至少要包含一道小题！", content));
            }

            for (int i = 0; i < subList.size(); i++) {
                QuDetailDTO item = subList.get(i);

                // 题库章节等属性直接使用大题的
                item.setRepoId(qu.getRepoId());
                item.setChapterId(qu.getChapterId());
                item.setLevel(qu.getLevel());

                this.checkData(item);
            }

            return;
        }

        // 单选、多选、判断、填空校验
        if (QuType.RADIO.equals(quType)
                || QuType.MULTI.equals(quType)
                || QuType.JUDGE.equals(quType)
                || QuType.FILL.equals(quType)) {

            if (CollectionUtils.isEmpty(answers)) {
                throw new ServiceException(MessageFormat.format("题目：【{0}】，客观题至少要包含一个备选答案！", content));
            }

            int trueCount = 0;
            for (QuAnswerDTO a : answers) {

                if (a.getIsRight() == null && !QuType.FILL.equals(qu.getQuType())) {
                    throw new ServiceException(MessageFormat.format("题目：【{0}】，必须定义选项是否正确项！", content));
                }

                if (StringUtils.isEmpty(a.getContent()) && StringUtils.isEmpty(a.getImage())) {
                    throw new ServiceException(MessageFormat.format("题目：【{0}】，选项内容或图片至少一项不为空！", content));
                }

                if (a.getIsRight()) {
                    trueCount += 1;
                }
            }

            if (trueCount == 0 && !QuType.FILL.equals(qu.getQuType())) {
                throw new ServiceException(MessageFormat.format("题目：【{0}】，至少要包含一个正确项！", content));
            }

            // 单选题
            if (qu.getQuType().equals(QuType.RADIO) && trueCount > 1) {
                throw new ServiceException(MessageFormat.format("题目：【{0}】，单选题不能包含多个正确项！", content));
            }

        }

    }

    /**
     * 查找组合题的子题目
     * 
     * @param quId
     * @return
     */
    public List<QuDetailDTO> listSub(String quId) {
        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(Qu::getChild, true)
                .eq(Qu::getRefId, quId)
                .orderByAsc(Qu::getSort);

        List<Qu> list = this.list(wrapper);
        if (!CollectionUtils.isEmpty(list)) {
            List<QuDetailDTO> respList = BeanMapper.mapList(list, QuDetailDTO.class);

            for (QuDetailDTO item : respList) {
                // 普通答案选项
                List<QuAnswerDTO> answerList = quAnswerService.listByQu(item.getId());
                item.setAnswerList(answerList);
            }

            return respList;
        }

        return new ArrayList<>();
    }

    @Override
    public String saveById(QuDetailDTO reqDTO) {
        // 校验数据
        this.checkData(reqDTO);

        Qu qu = new Qu();
        BeanMapper.copy(reqDTO, qu);

        // 更新
        this.saveOrUpdate(qu);

        // 保存全部问题
        quAnswerService.saveAll(qu.getId(), reqDTO.getAnswerList());

        // 保存组合题
        if (QuType.MIX.equals(reqDTO.getQuType())) {
            List<QuDetailDTO> subList = reqDTO.getSubList();

            int i = 1;
            for (QuDetailDTO item : subList) {
                // 保存子题目
                Qu sub = new Qu();
                BeanMapper.copy(item, sub);
                sub.setChild(true);
                sub.setRefId(qu.getId());
                sub.setSort(i);
                // 更新
                this.saveOrUpdate(sub);
                // 保存全部问题
                quAnswerService.saveAll(sub.getId(), item.getAnswerList());
                i++;
            }
        }
        return qu.getId();
    }

    // 移除关联的子题目
    private void removeRefs(List<String> ids) {

        QueryWrapper<Qu> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .select(Qu::getId)
                .in(Qu::getRefId, ids);

        // 子题列表
        List<Qu> list = this.list(wrapper);

        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        List<String> subIds = new ArrayList<>();
        for (Qu item : list) {
            subIds.add(item.getId());
        }

        // 移除子题
        this.removeByIds(ids);

        // 移除答案
        quAnswerService.removeByQuIds(subIds);

    }

    /**
     * 根据传入 JSON 构建题目详情对象（支持子题与答案）
     */
    private QuDetailDTO parseJsonToDetail(JSONObject obj, String quTypeStr, String level) {
        QuDetailDTO dto = new QuDetailDTO();

        dto.setQuType(mapQuType(quTypeStr));

        // 内容与解析：支持 question、content
        dto.setContent(firstNonBlank(obj.getString("question"), obj.getString("content")));
        dto.setAnalysis(obj.getString("analysis"));
        dto.setLevel(firstNonBlank(obj.getString("level"), level));

        List<QuAnswerDTO> answerList = new ArrayList<>();

        // 填空题处理
        if (QuType.FILL.equals(dto.getQuType())) {
            dto.setAnswerOrder(false); // 默认无序
            
            // 处理 answer 数组，转换为 answerList
            JSONArray answers = obj.getJSONArray("answer");
            if (answers != null && !answers.isEmpty()) {
                for (int i = 0; i < answers.size(); i++) {
                    QuAnswerDTO qa = new QuAnswerDTO();
                    qa.setContent(answers.getString(i));
                    qa.setIsRight(true); // 填空题答案都是正确的
                    answerList.add(qa);
                }
            }
        }
        // 单选题处理
        else if (QuType.RADIO.equals(dto.getQuType())) {
            // 处理选项列表：支持 choose、choices、options
            JSONArray choices = firstNonNullArray(
                obj.getJSONArray("choose"), 
                obj.getJSONArray("choices"), 
                obj.getJSONArray("options")
            );
            
            String correctAnswer = obj.getString("answer");
            
            if (choices != null) {
                for (int i = 0; i < choices.size(); i++) {
                    QuAnswerDTO qa = new QuAnswerDTO();
                    String choiceContent = choices.getString(i);
                    qa.setContent(choiceContent);
                    // 判断是否为正确答案
                    qa.setIsRight(choiceContent.equals(correctAnswer));
                    answerList.add(qa);
                }
            }
        }
        // 多选题处理
        else if (QuType.MULTI.equals(dto.getQuType())) {
            JSONArray choices = firstNonNullArray(
                obj.getJSONArray("choose"), 
                obj.getJSONArray("choices"), 
                obj.getJSONArray("options")
            );
            
            JSONArray correctAnswers = obj.getJSONArray("answer");
            List<String> correctList = new ArrayList<>();
            if (correctAnswers != null) {
                for (int i = 0; i < correctAnswers.size(); i++) {
                    correctList.add(correctAnswers.getString(i));
                }
            }
            
            if (choices != null) {
                for (int i = 0; i < choices.size(); i++) {
                    QuAnswerDTO qa = new QuAnswerDTO();
                    String choiceContent = choices.getString(i);
                    qa.setContent(choiceContent);
                    qa.setIsRight(correctList.contains(choiceContent));
                    answerList.add(qa);
                }
            }
        }
        // 判断题处理
        else if (QuType.JUDGE.equals(dto.getQuType())) {
            String answer = obj.getString("answer");
            boolean isTrue = "true".equalsIgnoreCase(answer) || "正确".equals(answer) || "T".equalsIgnoreCase(answer);
            
            // 添加"正确"选项
            QuAnswerDTO trueAnswer = new QuAnswerDTO();
            trueAnswer.setContent("正确");
            trueAnswer.setIsRight(isTrue);
            answerList.add(trueAnswer);
            
            // 添加"错误"选项
            QuAnswerDTO falseAnswer = new QuAnswerDTO();
            falseAnswer.setContent("错误");
            falseAnswer.setIsRight(!isTrue);
            answerList.add(falseAnswer);
        }

        dto.setAnswerList(answerList);

        // 处理子题目（组合题）
        JSONArray subList = obj.getJSONArray("subList");
        if (subList != null && !subList.isEmpty()) {
            dto.setQuType(QuType.MIX); // 强制设为组合题
            List<QuDetailDTO> subQuestions = new ArrayList<>();
            for (int i = 0; i < subList.size(); i++) {
                JSONObject subObj = subList.getJSONObject(i);
                String subType = firstNonBlank(
                    subObj.getString("questType"), 
                    subObj.getString("quType"), 
                    subObj.getString("type")
                );
                QuDetailDTO subDto = parseJsonToDetail(subObj, subType, level);
                subQuestions.add(subDto);
            }
            dto.setSubList(subQuestions);
        }

        return dto;
    }

    /**
     * 获取第一个非空的 JSONArray
     */
    private JSONArray firstNonNullArray(JSONArray... arrays) {
        if (arrays == null) {
            return null;
        }
        for (JSONArray array : arrays) {
            if (array != null && !array.isEmpty()) {
                return array;
            }
        }
        return null;
    }

    /**
     * 将外部题型字符串映射成系统题型编码
     */
    private String mapQuType(String type) {
        if (StringUtils.isEmpty(type)) {
            throw new ServiceException("题型不能为空！");
        }
        String t = type.trim().toLowerCase();
        switch (t) {
            case "radio":
            case "single":
            case "choice":
            case "choose":
            case "单选题":
                return QuType.RADIO;
            case "multi":
            case "multiple":
            case "多选题":
                return QuType.MULTI;
            case "judge":
            case "true_false":
            case "判断题":
                return QuType.JUDGE;
            case "saq":
            case "short":
            case "short_answer":
            case "简答题":
                return QuType.SAQ;
            case "fill":
            case "filling":
            case "blank":
            case "填空题":
                return QuType.FILL;
            case "link":
            case "连线题":
                return QuType.LINK;
            case "mix":
            case "composite":
            case "组合题":
                return QuType.MIX;
            default:
                // 兼容已经是内部编码的场景
                if (QuType.RADIO.equals(type) || QuType.MULTI.equals(type) || QuType.JUDGE.equals(type)
                        || QuType.SAQ.equals(type) || QuType.FILL.equals(type) || QuType.LINK.equals(type)
                        || QuType.MIX.equals(type)) {
                    return type;
                }
                throw new ServiceException("不支持的题型：" + type);
        }
    }

    private String firstNonBlank(String... arr) {
        if (arr == null) {
            return null;
        }
        for (String s : arr) {
            if (!StringUtils.isEmpty(s)) {
                return s;
            }
        }
        return null;
    }
}
